package com.moco.launcher.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.os.Handler;

public class WaveView extends View {
	public static final int STATE_DRAW_NONE = 0;
	public static final int STATE_DRAW_LINE = 1;
	public static final int STATE_DRAW_CIRCLE = 2;

	private static final int NUM = 3;
	private static final int K = 2;
	private static final int F = 3;// 2;
	private static final float ATT[] = { 1f, 1.7f, -2.3f, 3f, -4f };
	private static final float LINE_WIDTH[] = { 3f, 2f, 1f, 0.6f, 0.3f };
	// private static final int LINE_COLOR[] = {0xFFFFFFFF, 0x66FFFFFF,
	// 0x20FFFFFF, 0x66FFFFFF, 0x33FFFFFF};
	private static final int LINE_COLOR[] = { 0xffee7b1d, 0x66ee7b1d,
			0x20ee7b1d, 0x66ee7b1d, 0x33ee7b1d };

	private static final double GLOBAL_ATT[] = { 0.012345679012345675,
			0.013021399500554927, 0.013732813864772521, 0.014481660153984164,
			0.01526974701292647, 0.016098955301671804, 0.016971239637264577,
			0.017888629844218306, 0.018853232299839297, 0.01986723115949593,
			0.020932889446111668, 0.022052549987327582, 0.023228636182969394,
			0.024463652584667355, 0.025760185268729564, 0.027120901982665164,
			0.028548552045108463, 0.03004596597831617, 0.031616054851911914,
			0.03326180931614641, 0.034986298302642695, 0.036792667370413965,
			0.038684136674897555, 0.040663998537847135, 0.04273561459619141,
			0.04490241250840685, 0.04716788219758448, 0.049535571611207065,
			0.052009081978709404, 0.05459206254917936, 0.05728820479308656,
			0.06010123605370736, 0.06303491263595581, 0.06609301232264228,
			0.06927932631076407, 0.07259765056329133, 0.07605177657504289,
			0.07964548155465524, 0.08338251802831292, 0.08726660287483744,
			0.09130140580589552, 0.09549053730948075, 0.0998375360794131,
			0.10434585595837509, 0.1090188524269197, 0.11385976867591896,
			0.11887172130503305, 0.12405768569491954, 0.12942048110604046,
			0.13496275556199427, 0.14068697058026366, 0.14659538581806233,
			0.15269004370554007, 0.15897275414288492, 0.1654450793418225,
			0.17210831889554348, 0.17896349516419024, 0.18601133906558517,
			0.19325227636289616, 0.2006864145422769, 0.20831353037423747,
			0.216133058252451, 0.22414407940293618, 0.23234531205497622,
			0.24073510266275894, 0.2493114182635142, 0.25807184005388684,
			0.2670135582614165, 0.2761333683823082, 0.2854276688501998,
			0.2948924601933925, 0.30452334573004963, 0.3143155338422499,
			0.32426384186055224, 0.3343627015809738, 0.344606166426083,
			0.35498792025133524, 0.3655012877869515, 0.3761392466946375,
			0.3868944412073827, 0.3977591973095572, 0.40872553940367123,
			0.4197852083995599, 0.43092968115153873, 0.4421501911593254,
			0.45343775043934986, 0.4647831724646022, 0.4761770960634063,
			0.4876100101606392, 0.4990722792389258, 0.5105541693923249,
			0.5220458748410518, 0.5335375447728198, 0.5450193103745651,
			0.5564813119175286, 0.5679137257590261, 0.5793067911256324,
			0.5906508365449877, 0.6019363057968965, 0.6131537832588687,
			0.6242940185265935, 0.635347950196066, 0.6463067287010477,
			0.6571617381072316, 0.6679046167727355, 0.678527276793331,
			0.6890219221600155, 0.6993810655660421, 0.7095975438102455,
			0.719664531753386, 0.7295755547941012, 0.7393244998409014,
			0.7489056247663157, 0.7583135663387842, 0.7675433466370102,
			0.7765903779603053, 0.7854504662567858, 0.7941198130991549,
			0.8025950162451205, 0.8108730688262586, 0.8189513572152672,
			0.8268276576270653, 0.8345001315140823, 0.841967319820267,
			0.8492281361619335, 0.8562818590064472, 0.863128122922052,
			0.8697669089737631, 0.8761985343413287, 0.8824236412357271,
			0.8884431851906055, 0.894258422804512, 0.8998708990087044,
			0.9052824339338738, 0.9104951094472177, 0.9155112554291064,
			0.9203334358560142, 0.9249644347536138, 0.9294072420808533,
			0.9336650396026325, 0.9377411868052783, 0.941639206905537,
			0.945362773000182, 0.9489156943997216, 0.9523019031860063,
			0.9555254410298903, 0.9585904463014788, 0.961501141501938,
			0.9642618210423378, 0.9668768393916333, 0.969350599612599,
			0.9716875423013837, 0.9738921349433571, 0.9759688616950262,
			0.9779222135991382, 0.9797566792374919, 0.9814767358236335,
			0.9830868407353877, 0.9845914234851226, 0.9859948781237772,
			0.9873015560729619, 0.9885157593778854, 0.9896417343724908,
			0.9906836657468945, 0.9916456710061982, 0.9925317953087373,
			0.993346006671038, 0.9940921915260866, 0.9947741506209272,
			0.9953955952391711, 0.9959601437336713, 0.9964713183543688,
			0.9969325423561731, 0.9973471373716968, 0.9977183210336784,
			0.998049204832032, 0.9983427926017588, 0.9986019774730253,
			0.9988295417859142, 0.9990281552171841, 0.9992003735922634,
			0.9993486378468814, 0.9994752731255203, 0.9995824880043438,
			0.9996723738267381, 0.9997469041401918, 0.9998079342237094,
			0.9998572006955867, 0.9998963211661647, 0.9999267940670956,
			0.9999499983409533, 0.999967193321017, 0.9999795186083856,
			0.9999879939807399, 0.9999935193283541, 0.9999968746026366,
			0.999998719794656, 0.9999995949130265, 0.9999999199741996,
			0.9999999949967737, 1.0, 0.9999999950032255, 0.999999920025817,
			0.9999995950872363, 0.999998720207596, 0.9999968754091589,
			0.9999935207220179, 0.9999879961938128, 0.9999795219118294,
			0.9999671980244793, 0.9999500047927522, 0.9999268026541903,
			0.9998963323141244, 0.9998572148358125, 0.9998079518834245,
			0.9997469258592149, 0.999672400183134, 0.9995825196143118,
			0.999475310643256, 0.9993486819644068, 0.9992004250392342,
			0.9990282147606567, 0.9988296102300751, 0.9986020556588813,
			0.998342881406778, 0.9980493051697373, 0.997718433853165,
			0.9973472636571465, 0.9969326831262517, 0.9964714746615737,
			0.995960316663604, 0.995395785909733, 0.9947743601814328,
			0.9940924211562865, 0.993346257580053, 0.9925320687338935,
			0.9916459682117585, 0.990683988022683, 0.9896420830324107,
			0.9885161357583155, 0.9873019615310326, 0.9859953140355298,
			0.9845918912435309, 0.9830873417482537, 0.9814772715113519,
			0.9797572510306714, 0.9779228229360881, 0.9759695100191016,
			0.9738928237001625, 0.9716882729358367, 0.9693513735658476,
			0.9668776580978403, 0.9642626859253214, 0.9615020539716782,
			0.9585914077504927, 0.9555264528294761, 0.9523029666823717,
			0.9489168109099905, 0.9453639438082962, 0.9416404332580616,
			0.9377424699071121, 0.9336663806126438, 0.9294086421074498,
			0.9249658948502589, 0.9203349570167072, 0.9155128385838398,
			0.9104967554574267, 0.9052841435879027, 0.8998726730173026,
			0.8942602617963819, 0.8884450897080249, 0.8824256117302627,
			0.8762005711696715, 0.8697690123937021, 0.8631302930886133,
			0.8562840959682227, 0.8492304398576208, 0.8419696900754503,
			0.8345025680382712, 0.8268301600110293, 0.8189539249286708,
			0.8108757012156389, 0.8025977125322135, 0.79412257237961,
			0.7854532874992675, 0.7765932600060181, 0.767546288199655,
			0.7583165660049661, 0.7489086809964108, 0.7393276109703959,
			0.7295787190354154, 0.719667747198179, 0.7096008084322181,
			0.69938437722422, 0.6890252786025255, 0.6785306756616561,
			0.6679080556064424, 0.6571652143491558, 0.6463102397029242,
			0.6353514932245845, 0.6242975907698565, 0.613157381833228,
			0.601939927754142, 0.5906544788798544, 0.5793104507835969,
			0.5679173996443517, 0.556484996901531, 0.5450230033040453,
			0.5335412424786375, 0.5220495741467882, 0.510557867122994,
			0.49907597222968964, 0.48761369526548826, 0.47618077016374977,
			0.464786832477738, 0.45344139332676087, 0.4421538139347651,
			0.4309332808888671, 0.41978878224028493, 0.40872908456416807,
			0.3977627110879246, 0.3868979209899061, 0.37614268996183403,
			0.36550469211916636, 0.3549912833338707, 0.34460948605383807,
			0.33436597566258336, 0.3242670684220074, 0.314318711029998,
			0.30452647181356374, 0.2948955335672114, 0.28543068803544036,
			0.27613633202765475, 0.2670164651435974, 0.258074689077648,
			0.24931420846110602, 0.24073783319295122, 0.23234798220162467,
			0.22414668857311998, 0.21613560597420345, 0.20831601629390037,
			0.2006888384215006, 0.19325463807531665, 0.18601363859320588,
			0.17896573259349838, 0.17211049441339224, 0.16544719323110593,
			0.15897480677804127, 0.15269203554790697, 0.1465973174111181,
			0.14068884254477987, 0.13496456859112976, 0.129422235960401,
			0.12405938319760973, 0.11887336233672456, 0.11386135416995653,
			0.10902038336448751, 0.10434733336374145, 0.09983896101527175,
			0.09549191087240562, 0.09130272912192303, 0.08726787709518866,
			0.08338374432526778, 0.07964666111758775, 0.07605291060662595,
			0.0725987402758772, 0.0692803729229462, 0.0660940170560014,
			0.06303587671199401, 0.060102160690969894, 0.05728909120447248,
			0.05459291193943988, 0.052009895542131604, 0.04953635052948052,
			0.047168627637847335, 0.044903125621466256, 0.042736296514914555,
			0.0406646503757166, 0.0386847595247253, 0.036793262303207626,
			0.03498686636661797, 0.03326235153587815, 0.03161657222761742,
			0.030046459485263313, 0.02854902263314153, 0.027121350575841512,
			0.025760612765059473, 0.024464059855950394, 0.023229024074720377,
			0.02205291931878504, 0.020933241010322557, 0.01986756572346994,
			0.018853550604766553, 0.017888932605744774, 0.016971527545818987,
			0.01609922902283915, 0.015270007187862361, 0.014481907399865735,
			0.013733048775280518, 0.01302162264638321, 0.012345890941733696, };

	private double phase = 0;
	private float speed = 0.5f;// 0.15f;
	private float noise = 0.0f;// 0.02f;

	private float curNoise = 0.0f;
	private float preNoise = 0.0f;

	private int mHalfViewWidth;
	private int mHalfViewHeight;
	private Paint mPaint, mCirclePaint;
	private Path[] mWavePaths;

	private float rotate_speed = 5;
	private float circle_radius = 100;
	private float mRotate = 0;
	private Matrix mMatrix = new Matrix();
	private Shader mShader;

	private int mState = 0;

	private boolean mRecordingState = false;
	private Handler mHandler;
	private float mStep = 0.0f;
	private float mPreStep = 0.0f;
	private float mCurStep = 0.0f;
	private int AMPLITUDE_TIMER_ID = 1;
	private boolean mUp = true;
	private Context mContext;

	public WaveView(Context context) {
		super(context);
		init(context);
	}

	public WaveView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	public WaveView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	@SuppressLint("NewApi")
	private void init(Context context) {
		this.setLayerType(LAYER_TYPE_HARDWARE, null);
		mContext = context;
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mPaint.setStyle(Style.STROKE);

		mCirclePaint = new Paint();
		mCirclePaint.setAntiAlias(true);
		mCirclePaint.setStyle(Style.STROKE);
		mCirclePaint.setStrokeWidth(LINE_WIDTH[0]);
		mWavePaths = new Path[NUM];
		for (int i = 0; i < NUM; i++) {
			mWavePaths[i] = new Path();
		}

		Resources res = context.getResources();
		rotate_speed = res.getDisplayMetrics().density * 2;

		// this.setBackgroundColor(Color.argb(60, 255, 0, 0));

		mHandler = new Handler() {
			@Override
			public void handleMessage(android.os.Message msg) {

				if (msg.what == AMPLITUDE_TIMER_ID) {

					if (mRecordingState) {

						if (preNoise < noise) {
							if (curNoise < noise) {
								curNoise += 0.08f;
							} else {
								curNoise = noise;
							}

						} else {
							if (curNoise > noise) {
								curNoise -= 0.04f;
							} else {
								curNoise = noise;
							}
						}

					} else {

						if (curNoise > 0.0f) {
							curNoise -= 0.04f;
						} else
							curNoise = 0.0f;

					}

					mHandler.sendEmptyMessageDelayed(AMPLITUDE_TIMER_ID, 20L);
				}
			}
		};
	}

	private boolean isUp() {
		return preNoise < noise;
	}

	private boolean isDown() {
		return preNoise > noise;
	}

	public void start() {
		mState = STATE_DRAW_LINE;
		this.mHandler.sendEmptyMessage(AMPLITUDE_TIMER_ID);
		postInvalidate();
	}

	public void stop() {
		mState = STATE_DRAW_NONE;
		noise = 0.02f;
	}

	public void setState(int state) {
		mState = state;
	}

	public void setRms(int rms) {
		/*
		 * noise = (noise + rms / 100.0f) / 2; if (noise < 0.1f) noise = 0.1f;
		 * else if (noise > 1f) noise = 1f;
		 */
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mHalfViewWidth = getMeasuredWidth() / 2;
		mHalfViewHeight = getMeasuredHeight() / 2;
		Log.d("dqm.waveview", "onMeasure width: " + mHalfViewWidth
				+ "  height: " + mHalfViewHeight);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// Log.d("dqm.voice", "~~~~~~~~~~~~~~  onDraw ~~~~~~~~~~~~~~~");

		switch (mState) {
		case STATE_DRAW_LINE:
			drawLine(canvas);
			invalidate();
			break;
		case STATE_DRAW_CIRCLE:
			drawCircle(canvas);
			// invalidate();
			break;
		default:
			break;
		}
	}

	private void drawLine(Canvas canvas) {
		for (int n = 0; n < NUM; n++) {
			mWavePaths[n].rewind();
			mWavePaths[n].moveTo(0, mHalfViewHeight);
		}

		float x, y;
		double tmp;
		int j = 0;
		phase = (phase + speed) % (Math.PI * 64);
		for (float i = -K; i <= K; i += 0.01) {
			x = mHalfViewWidth * ((i + K) / K);
			tmp = curNoise * Math.sin(F * i - phase) * GLOBAL_ATT[j++];

			for (int n = 0; n < NUM; n++) {
				y = (float) (mHalfViewHeight * (1 + tmp / ATT[n]));
				mWavePaths[n].lineTo(x, y);
			}
		}

		for (int n = 0; n < NUM; n++) {
			// mWavePaths[n].close();
			mPaint.setColor(LINE_COLOR[n]);
			mPaint.setStrokeWidth(LINE_WIDTH[n]);
			canvas.drawPath(mWavePaths[n], mPaint);
		}
	}

	private void drawCircle(Canvas canvas) {
		if (mShader == null) {
			mShader = new SweepGradient(mHalfViewWidth, mHalfViewHeight,
					new int[] { Color.WHITE, Color.TRANSPARENT }, new float[] {
							0.8f, 0.2f });
			mCirclePaint.setShader(mShader);
		}

		mMatrix.setRotate(-mRotate, mHalfViewWidth, mHalfViewHeight);
		mShader.setLocalMatrix(mMatrix);
		mRotate += rotate_speed;
		if (mRotate >= 360) {
			mRotate = 0;
		}
		canvas.drawCircle(mHalfViewWidth, mHalfViewHeight, circle_radius,
				mCirclePaint);
	}

	public void setAmplitude(int amplitude, boolean recordingState) {

		mRecordingState = recordingState;
		if (!recordingState) {
			return;
		}

		float f = (float) (amplitude) / 48000 * 2.0f;
		if (f > 0.99f)
			f = 0.99f;

		if (f < 0.1f) {
			f = 0.1f;
		}

		if (f == noise)
			return;

		if (curNoise != noise) {
			if (noise < f && preNoise < noise) {
				preNoise = noise;
				noise = f;
			}

			return;
		}

		preNoise = noise;
		noise = f;

	}

	private double globalAttenuationFn(float x) {
		return Math.pow(K * 4 / (K * 4 + Math.pow(x, 4)), K * 2);
	}
}
